<?php
/**
 * SocialEngine
 *
 * @category   Application_Extensions
 * @package    Wall
 * @copyright  Copyright Hire-Experts LLC
 * @license    http://www.hire-experts.com
 * @version    $Id: Actions.php 2011-04-26 11:18:13 michael $
 * @author     Michael
 */

/**
 * @category   Application_Extensions
 * @package    Wall
 * @copyright  Copyright Hire-Experts LLC
 * @license    http://www.hire-experts.com
 */

class Wall_Model_DbTable_Actions extends Activity_Model_DbTable_Actions {
	protected $_rowClass = 'Wall_Model_Action';
	protected $_name = 'activity_actions';
	
	public function getActivity(User_Model_User $user, array $params = array()) {
		// Proc args
		extract ( $this->_getInfo ( $params ) ); // action_id, limit, min_id, max_id
		$items = (isset ( $params ['items'] )) ? $params ['items'] : null;
		
		// Prepare main query
		$streamTable = Engine_Api::_ ()->getDbtable ( 'stream', 'activity' );
		$db = $streamTable->getAdapter ();
		$union = new Zend_Db_Select ( $db );
		
		// Prepare action types
		$masterActionTypes = Engine_Api::_ ()->getDbtable ( 'actionTypes', 'activity' )->getActionTypes ();
		
		$mainActionTypes = array ();
		$subjectActionTypes = array ();
		$objectActionTypes = array ();
		
		// Filter out types set as not displayable
		foreach ( $masterActionTypes as $type ) {
			if ($type->displayable & 4) {
				$mainActionTypes [] = $type->type;
			}
			if ($type->displayable & 1) {
				$subjectActionTypes [] = $type->type;
			}
			if ($type->displayable & 2) {
				$objectActionTypes [] = $type->type;
			}
		}
		
		// Filter types based on user request
		if (isset ( $showTypes ) && is_array ( $showTypes ) && ! empty ( $showTypes )) {
			$mainActionTypes = array_intersect ( $mainActionTypes, $showTypes );
			$subjectActionTypes = array_intersect ( $subjectActionTypes, $showTypes );
			$objectActionTypes = array_intersect ( $objectActionTypes, $showTypes );
		} else if (isset ( $hideTypes ) && is_array ( $hideTypes ) && ! empty ( $hideTypes )) {
			$mainActionTypes = array_diff ( $mainActionTypes, $hideTypes );
			$subjectActionTypes = array_diff ( $subjectActionTypes, $hideTypes );
			$objectActionTypes = array_diff ( $objectActionTypes, $hideTypes );
		}
		
		// Nothing to show
		if (empty ( $mainActionTypes ) && empty ( $subjectActionTypes ) && empty ( $objectActionTypes )) {
			return null;
		}
		
		if (empty ( $mainActionTypes )) {
			$mainActionTypes = null;
		} else if (count ( $mainActionTypes ) == count ( $masterActionTypes )) {
			$mainActionTypes = true;
		} else {
			$mainActionTypes = "'" . join ( "', '", $mainActionTypes ) . "'";
		}
		
		if (empty ( $subjectActionTypes )) {
			$subjectActionTypes = null;
		} else if (count ( $subjectActionTypes ) == count ( $masterActionTypes )) {
			$subjectActionTypes = true;
		} else {
			$subjectActionTypes = "'" . join ( "', '", $subjectActionTypes ) . "'";
		}
		
		if (empty ( $objectActionTypes )) {
			$objectActionTypes = null;
		} else if (count ( $objectActionTypes ) == count ( $masterActionTypes )) {
			$objectActionTypes = true;
		} else {
			$objectActionTypes = "'" . join ( "', '", $objectActionTypes ) . "'";
		}
		
		if ($items !== null) {
			
			if (empty ( $items )) {
				return null;
			}
			
			$items = Engine_Api::_ ()->wall ()->setItemsGuid ( $items );
			$typeItems = Engine_Api::_ ()->wall ()->setItemsType ( $items );
			
			$subjectSelect = $streamTable->select ()->from ( $streamTable->info ( 'name' ), array ('type' => 'subject_type', 'id' => 'subject_id' ) );
			
			foreach ( $typeItems as $type => $ids ) {
				
				$str_ids = implode ( ",", $ids );
				$subjectSelect->orWhere ( new Zend_Db_Expr ( "(subject_type = '$type' AND subject_id IN ($str_ids))" ) );
			
			}
			
			$objectSelect = $streamTable->select ()->from ( $streamTable->info ( 'name' ), array ('type' => 'object_type', 'id' => 'object_id' ) );
			
			foreach ( $typeItems as $type => $ids ) {
				
				$str_ids = implode ( ",", $ids );
				$objectSelect->orWhere ( new Zend_Db_Expr ( "(object_type = '$type' AND object_id IN ($str_ids))" ) );
			
			}
			
			$select = new Zend_Db_Select ( $db );
			
			if (null !== $action_id) {
				$subjectSelect->where ( 'action_id = ?', $action_id );
				$objectSelect->where ( 'action_id = ?', $action_id );
			} else {
				if (null !== $min_id) {
					$subjectSelect->where ( 'action_id >= ?', $min_id );
					$objectSelect->where ( 'action_id >= ?', $min_id );
				} else if (null !== $max_id) {
					$subjectSelect->where ( 'action_id <= ?', $max_id );
					$objectSelect->where ( 'action_id <= ?', $max_id );
				}
			}
			
			if (null !== $hideIds) {
				$subjectSelect->where ( 'action_id NOT IN(?)', $hideIds );
				$objectSelect->where ( 'action_id NOT IN(?)', $hideIds );
			}
			
			$subjectSelect->order ( 'action_id DESC' )->limit ( $limit );
			
			$objectSelect->order ( 'action_id DESC' )->limit ( $limit );
			
			$select->union ( array ('(' . $subjectSelect->__toString () . ')' ) )->union ( array ('(' . $objectSelect->__toString () . ')' ) );
			
			// replace and set unique
			$items = Engine_Api::_ ()->wall ()->setItemsGuid ( $select->query ()->fetchAll () );
			
			$items_list = array ();
			foreach ( Engine_Api::_ ()->wall ()->getItems ( $items ) as $item ) {
				$items_list [$item->getGuid ()] = $item;
			}
			
			$mixedResponses = array ();
			
			foreach ( $items_list as $key => $about ) {
				
				$event = Engine_Hooks_Dispatcher::getInstance ()->callEvent ( 'getActivity', array ('for' => $user, 'about' => $about ) );
				
				$responses = ( array ) $event->getResponses ();
				
				if (empty ( $responses )) {
					continue;
				}
				
				$mixedResponses [$about->getGuid ()] = $responses;
			
			}
			
			if (empty ( $mixedResponses )) {
				return null;
			}
			
			foreach ( $mixedResponses as $guid => $responses ) {
				
				$about = $items_list [$guid];
				if (! $about) {
					continue;
				}
				
				foreach ( $responses as $response ) {
					if (empty ( $response ))
						continue;
					
		// Target info
					$select = $streamTable->select ()->from ( $streamTable->info ( 'name' ), 'action_id' )->where ( 'target_type = ?', $response ['type'] );
					
					if (empty ( $response ['data'] )) {
						// Simple
						$select->where ( 'target_id = ?', 0 );
					} else if (is_scalar ( $response ['data'] ) || count ( $response ['data'] ) === 1) {
						// Single
						if (is_array ( $response ['data'] )) {
							list ( $response ['data'] ) = $response ['data'];
						}
						$select->where ( 'target_id = ?', $response ['data'] );
					} else if (is_array ( $response ['data'] )) {
						// Array
						$select->where ( 'target_id IN(?)', ( array ) $response ['data'] );
					} else {
						// Unknown
						continue;
					}
					
					// Add action_id/max_id/min_id
					if (null !== $action_id) {
						$select->where ( 'action_id = ?', $action_id );
					} else {
						if (null !== $min_id) {
							$select->where ( 'action_id >= ?', $min_id );
						} else if (null !== $max_id) {
							$select->where ( 'action_id <= ?', $max_id );
						}
					}
					
					if (null !== $hideIds) {
						$select->where ( 'action_id NOT IN(?)', $hideIds );
					}
					
					// Add order/limit
					$select->order ( 'action_id DESC' )->limit ( $limit );
					
					// Add subject to main query
					$selectSubject = clone $select;
					if ($subjectActionTypes !== null) {
						if ($subjectActionTypes !== true) {
							$selectSubject->where ( 'type IN(' . $subjectActionTypes . ')' );
						}
						
						$selectSubject->where ( 'subject_type = ?', $about->getType () )->where ( 'subject_id = ?', $about->getIdentity () );
						$union->union ( array ('(' . $selectSubject->__toString () . ')' ) ); // (string) not work before PHP 5.2.0
					

					}
					
					// Add object to main query
					$selectObject = clone $select;
					if ($objectActionTypes !== null) {
						if ($objectActionTypes !== true) {
							$selectObject->where ( 'type IN(' . $objectActionTypes . ')' );
						}
						$selectObject->where ( 'object_type = ?', $about->getType () )->where ( 'object_id = ?', $about->getIdentity () );
						
						$union->union ( array ('(' . $selectObject->__toString () . ')' ) ); // (string) not work before PHP 5.2.0
					}
				}
			}
		
		} else {
			
			// Prepare sub queries
			$event = Engine_Hooks_Dispatcher::getInstance ()->callEvent ( 'getActivity', array ('for' => $user ) );
			$responses = ( array ) $event->getResponses ();
			
			if (empty ( $responses )) {
				return null;
			}
			
			foreach ( $responses as $response ) {
				if (empty ( $response ))
					continue;
				
				$select = $streamTable->select ()->from ( $streamTable->info ( 'name' ), 'action_id' )->where ( 'target_type = ?', $response ['type'] );
				
				if (empty ( $response ['data'] )) {
					// Simple
					$select->where ( 'target_id = ?', 0 );
				} else if (is_scalar ( $response ['data'] ) || count ( $response ['data'] ) === 1) {
					// Single
					if (is_array ( $response ['data'] )) {
						list ( $response ['data'] ) = $response ['data'];
					}
					$select->where ( 'target_id = ?', $response ['data'] );
				} else if (is_array ( $response ['data'] )) {
					// Array
					$select->where ( 'target_id IN(?)', ( array ) $response ['data'] );
				} else {
					// Unknown
					continue;
				}
				
				// Add action_id/max_id/min_id
				if (null !== $action_id) {
					$select->where ( 'action_id = ?', $action_id );
				} else {
					if (null !== $min_id) {
						$select->where ( 'action_id >= ?', $min_id );
					} else if (null !== $max_id) {
						$select->where ( 'action_id <= ?', $max_id );
					}
				}
				if (null !== $hideIds) {
					$select->where ( 'action_id NOT IN(?)', $hideIds );
				}
				
				if ($mainActionTypes !== true) {
					$select->where ( 'type IN(' . $mainActionTypes . ')' );
				}
				
				// Add order/limit
				$select->order ( 'action_id DESC' )->limit ( $limit );
				
				// Add to main query
				$union->union ( array ('(' . $select->__toString () . ')' ) ); // (string) not work before PHP 5.2.0
			}
		
		}
		
		// Finish main query
		$union->order ( 'action_id DESC' )->limit ( $limit );
		
		// Get actions
		$actions = $db->fetchAll ( $union );
		
		// No visible actions
		if (empty ( $actions )) {
			return null;
		}
		
		// Process ids
		$ids = array ();
		foreach ( $actions as $data ) {
			$ids [] = $data ['action_id'];
		}
		$ids = array_unique ( $ids );
		
		// Finally get activity
		return $this->fetchAll ( $this->select ()->where ( 'action_id IN(' . join ( ',', $ids ) . ')' )->order ( 'action_id DESC' )->limit ( $limit ) );
	
	}
	
	protected function _getInfo(array $params) {
		$settings = Engine_Api::_ ()->getApi ( 'settings', 'core' );
		$args = array ('limit' => $settings->getSetting ( 'activity.length', 20 ), 'action_id' => null, 'max_id' => null, 'min_id' => null, 'showTypes' => null, 'hideTypes' => null, 'hideIds' => null );
		
		$newParams = array ();
		foreach ( $args as $arg => $default ) {
			if (! empty ( $params [$arg] )) {
				$newParams [$arg] = $params [$arg];
			} else {
				$newParams [$arg] = $default;
			}
		}
		
		return $newParams;
	}

}